#include <iostream>
#include <typeinfo>
#include <cassert>
#include<any>

class Any
{
private:
    class holder
    {
    public:
        virtual ~holder() {}
        virtual const std::type_info& type() = 0;
        virtual holder *clone() = 0;
    };

    template <class T>
    class placeholder : public holder
    {
    public:
        placeholder(const T &val) : _val(val) {}
        ~placeholder() {
            std::cout << "placeholder<T>析构" << std::endl;
        }
        // 获取子类对象保存的数据类型
        virtual const std::type_info& type()
        {
            return typeid(T);
        }
        // 克隆当前的对象自身，返回一个新的对象
        virtual holder *clone()
        {
            return new placeholder<T>(_val);
        }

    public:
        T _val;
    };
    holder *_content;

public:
    Any() : _content(nullptr) {}
    template <class T>
    Any(const T &val) : _content(new placeholder<T>(val)) {}
    Any(const Any &other) : _content(other._content ? other._content->clone() : nullptr) {}
    
    ~Any()
    {
        delete _content;
    }

    Any &swap(Any &other)
    {
        std::swap(_content, other._content);
        return *this;
    }

    template <class T>
    // 返回子类对象保存的数据的指针
    T *get()
    {
        // 想要获取的数据类型，必须和保存的数据类型一致
        assert(typeid(T) == _content->type());
        return &((placeholder<T> *)_content)->_val;
    }
    template <class T>
    // 赋值运算符的重载函数
    Any &operator=(const T &val)
    {
        // 为val构造一个临时的通用容器，然后与当前容器自身进行指针交换，临时对象释放的时候，原来的数据就也被释放了
        Any(val).swap(*this);
        return *this;
    }
    Any &operator=(const Any &other)
    {
        Any(other).swap(*this);
        return *this;
    }
};


class test
{
    public:
     test(){std::cout<<"构造"<<std::endl;}
     ~test(){std::cout<<"析构"<<std::endl;}
};


int main()
{


    //标准库C++17里是Any的使用
    std::any a;
    a = 10;
    int *pi=std::any_cast<int>(&a);
    std::cout<<*pi<<std::endl;

    a=std::string("hello word");
    std::string* ps=std::any_cast<std::string>(&a);
    std::cout<<*ps<<std::endl;

    // Any a;
    // {
    //     test t;
    //     a = t;
    // }

    // a = 10; 
    // std::cout << *a.get<int>() << std::endl;
    // std::string str = "hello world";
    // a = str;
    // std::cout << *a.get<std::string>() << std::endl;
    
    return 0;
}